<?php

namespace app\cmini\service;

use \app\cmini\repository\FansRepository;
use \app\Jwt;
use think\facade\Cache;

/**
 * Class LoginService
 * @package app\cmini\service
 * @author sl
 * @create 2021-12-24 10:44
 */
class LoginService extends CommonService
{
    public function __construct()
    {
        $this->app_id       = env('cmini.app_id', '');
        $this->app_secret   = env('cmini.app_secret', '');
    }

    /**
     * 获取token
     * @param  array $request
     * @return array
     * @author sl
     * @create 2021-12-24 10:47
     */
    public function handleLoginData(array $request): array
    {
        try {
            $code               = $request['code'] ?? '';
            $telEncryptedData   = $request['tel_encrypted'] ?? '';
            $telIv              = $request['tel_iv'] ?? '';
            $fansEncryptedData  = $request['fans_encrypted'] ?? '';
            $fansIv             = $request['fans_iv'] ?? '';
            if(!$code || !$telEncryptedData || !$telIv || !$fansEncryptedData || !$fansIv)
            {
                $this->code  = 401;
                $this->error = '参数错误';
                return [];
            }
            
            // 通过code获取session_key、openid
            $requestUrl = "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code";
            $requestUrl = sprintf($requestUrl, $this->app_id, $this->app_secret, $code);
            $response   = $this->getCurl($requestUrl);
            if(isset($response['errcode']))
            {
                $this->error = $response['errmsg'];
                return [];
            }

            $openid      = $response['openid'] ?? '';
            $session_key = $response['session_key'] ?? '';

            // 通过encryptedData、iv、session_key获取用户手机号
            $telRes = $this->decryptData($telEncryptedData, $telIv, $session_key, $tel_data);
            if(!$telRes)
            {
                $this->code  = 401;
                $this->error = '获取手机号失败，请重试！';
                return [];
            }

            // 通过encryptedData、iv、session_key获取用户信息
            $fansRes = $this->decryptData($fansEncryptedData, $fansIv, $session_key, $fans_data);
            if(!$fansRes)
            {
                $this->code  = 401;
                $this->error = '获取用户信息失败，请重试！';
                return [];
            }
            
            // 查询用户是否已注册
            $field = ['id'];
            $fansInfo = FansRepository::find(['openid' => $openid], $field);
            
            $data = [];
            $data['openId']     = $openid ?? '';
            $data['nickName']   = $fans_data['nickName'] ?? '';
            $data['gender']     = $fans_data['gender'] ?? 0;
            $data['country']    = $fans_data['country'] ?? 0;
            $data['province']   = $fans_data['province'] ?? 0;
            $data['city']       = $fans_data['city'] ?? 0;
            $data['avatarUrl']  = $fans_data['avatarUrl'] ?? '';
            $data['telephone']  = $tel_data['phoneNumber'] ?? '';
            $data['update_time']= date('Y-m-d H:i:s');
            
            // 已注册，更新用户数据；未注册，插入用户数据
            if($fansInfo)
            {
                $fansId = $fansInfo['id'];
                $updateRes = FansRepository::update(['id' => $fansId], $data);
            }
            else{
                $data['create_time'] = date('Y-m-d H:i:s');
                $fansId = FansRepository::insert($data);
            }

            // 生成token
            $token = Jwt::getToken(['fansId' => $fansId]);

            // 缓存或更新用户信息
            $oldFansInfo = (array) Cache::get('cmfans:MiniProgram-'.$fansId);
            $newFansInfo = 
            Cache::set('cmfans:MiniProgram-'.$fansId,array_merge($oldFansInfo,[
                'fansId'      =>  $fansId ?? 0,
                'sessionKey'  =>  $session_key ?? '',
                'openId'      =>  $openid ?? '',
                'token'       =>  $token,
                'telephone'   =>  $tel_data['phoneNumber'] ?? '',
                'nickName'    =>  $fans_data['nickName'] ?? '',
                'gender'      =>  $fans_data['gender'] ?? 0,
                'city'        =>  $fans_data['city'] ?? 0,
                'province'    =>  $fans_data['province'] ?? 0,
                'country'     =>  $fans_data['country'] ?? 0,
                'avatarUrl'   =>  $fans_data['avatarUrl'] ?? '',
            ]));
            
        } catch (\Exception $e) {
            throw new \Exception($e->getMessage(), $e->getCode());
        }

        $return = [];
        $fieldArr = ['id', 'nickName', 'gender', 'country', 'province', 'city', 'avatarUrl', 'telephone', 'create_time'];
        $return = FansRepository::find(['id' => $fansId], $fieldArr)->toArray();
        $return['token'] = $token;
        return $return ?? [];
    }

    /**
     * CURL GET请求
     */
    protected function getCurl($url)
    {
        $headerArray =array("Content-type:application/json;","Accept:application/json");
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE); 
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE); 
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl,CURLOPT_HTTPHEADER,$headerArray);
        $output = curl_exec($curl);
        curl_close($curl);
        $output = json_decode($output,true);
        return $output;
    }

    /**
     * 解密
     * error code 说明.
     * <ul>
     *    <li>-41001: encodingAesKey 非法</li>
     *    <li>-41003: aes 解密失败</li>
     *    <li>-41004: 解密后得到的buffer非法</li>
     *    <li>-41005: base64加密失败</li>
     *    <li>-41016: base64解密失败</li>
     * </ul>
     */
    protected function decryptData( $encryptedData, $iv, $sessionKey, &$data )
    {
        if (strlen($sessionKey) != 24)
        {
            // return -41001;
            return false;
        }
        $aesKey=base64_decode($sessionKey);

        if (strlen($iv) != 24) 
        {
            // return -41002;
            return false;
        }
        $aesIV=base64_decode($iv);

        $aesCipher=base64_decode($encryptedData);
        $result= openssl_decrypt( $aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV);
        if( is_bool($result) )
        {
            // return -41016;
            return false;
        }
        $dataObj= json_decode( $result);
        if( $dataObj  == NULL )
        {
            // return -41003;
            return false;
        }
        if( $dataObj->watermark->appid != $this->app_id )
        {
            // return -41003;
            return false;
        }
        $data = json_decode( $result,true);
        return true;
    }


    /**
     * 用户详情
     * @param  array $request
     * @return array
     * @author sl
     * @create 2021-12-20 13:40
     */
    public function detailData(array $request): array
    {
        $id = $request['id'] ?? 0;
        if(!$id)
        {
            $this->error = '参数错误';
            return [];
        }
        $fans = FansRepository::find(['id' => $id]);
        if(!$fans)
        {
            $this->code  = 404;
            $this->error = '用户不存在';
            return [];
        }

        $data = $fans->toArray();
        return $data ?? [];
    }

}